import {generateEventEmitter} from './generateEventEmitter';
import * as update from './update';
import get from 'lodash/get';

const noop = function () {
};
export const genModel = ({
    defaultData = () => {
        return {}
    },
    log = noop,
    showLog,
    ...other
} = {}) => {
    const event = generateEventEmitter();
    const rst = {
        data: defaultData()
    };

    const _changeData = (args = {}, path, method = 'update') => {
        const {
            action,
            param
        } = args;
        if (!action) {
            console.warn(`action不能为空`);
        }
        const oldData = rst.data;
        if(method==='replace'){
            rst.data={
                ...param
            };
        }else{
            const target = path ? get(oldData, path) : oldData;
            const newTarget=update[method](target, param);
            rst.data = path?update.update(oldData,{
                [path]:newTarget
            }):newTarget;
        }
        showLog && log('model.changeData',args,'path=',path);
        event.emit('change', oldData);
    };
    return {
        ...other,
        getData(path, defVal) {
            return path ?
                get(rst.data, path, defVal) :
                rst.data;
        },
        resetData(data=defaultData()){
            _changeData({
                action:'resetData',
                param:data
            },null,'replace');
        },
        onChange(ns, fn) {
            return event.onOne('change', ns, fn);
        },
        offChange(ns,fn){
            return event.off('change', ns, fn);
        },
        off(...args) {
            return event.off(...args);
        },
        offAll(){
            return event.removeAllListeners();
        },
        changeData(...args) {
            if (args.length === 2) {
                return _changeData(args[1], args[0])
            }
            return _changeData(args[0]);
        },
        //todo:kule 临时解决循环触发的问题，优化至emit的最后一个listener调用后触发
        changeDataNoEmit(...args){
            setTimeout(()=>{
                this.changeData(...args);
            },1);
        },
        nextTick(fn){
            setTimeout(()=>{
                fn&&fn();
            },1);
        },
        changeDataUseImmutable(arg) {
            return _changeData(arg, null, 'updateRaw');
        }
    }
};
export default genModel;